/*
** Copyright (C) 2010 Calin Radoni
**
** This file is part of CHScanner.
**
** CHScanner is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** CHScanner is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with CHScanner. If not, see <http://www.gnu.org/licenses/>.
*/

#include "StdAfx.h"
#include "PacketBuilderEx6.h"

#include <Winsock2.h>

//---------------------------------------------------------------------------

PacketBuilderEx6::PacketBuilderEx6(void) :PacketBuilder6()
{
	mimicInfoPack.Set(__mosRandom);
}

PacketBuilderEx6::~PacketBuilderEx6(void)
{
}

//---------------------------------------------------------------------------

void PacketBuilderEx6::SetMimic(MimicOS mosIn)
{
	mimicInfoPack.Set(mosIn);
}

//---------------------------------------------------------------------------

int PacketBuilderEx6::BuildSynOptions(BYTE* buff)
{
	DWORD dwVal;
	BYTE* bVal;
	int retVal;

	MimicOS myMimic;

	if(buff==NULL) return 0;

	myMimic = mimicInfoPack.GetMimic();

	switch(myMimic){
		case __mosWindowsXPSP2 :
			buff[0] = 0x02;		// RFC 0793 : Maximum Segment Size, length = 4
			buff[1] = 0x04;
			buff[2] = 0x05;
			buff[3] = 0xA0;

			retVal = 4;
			break;

		case __mosWindows2K3 :
			buff[0] = 0x02;		// RFC 0793 : Maximum Segment Size, length = 4
			buff[1] = 0x04;
			buff[2] = 0x05;
			buff[3] = 0xA0;

			retVal = 4;
			break;

		case __mosLinux_2_4:
			retVal = 0;
			break;

		case __mosLinux_2_6:
			dwVal = GetTickCount();
			bVal  = (BYTE*)&dwVal;

			buff[0]  = 0x02; buff[1]  = 0x04; buff[2]  = 0x05; buff[3]  = 0xA0;	// RFC 0793 : Maximum Segment Size, length = 4

			buff[4]  = 0x04; buff[5]  = 0x02;									// RFC 2018 : Sack-Permitted Option, length = 2

			buff[6]  = 0x08;    buff[7]  = 0x0A;								// RFC 1323 : Timestamps Option, length = 10
			buff[8]  = bVal[0]; buff[9]  = bVal[1];								//		- Timestamp Value field
			buff[10] = bVal[2]; buff[11] = bVal[3];								//		- Timestamp Value field (continued)
			buff[12] = 0x00;    buff[13] = 0x00;								//		- Timestamp Echo Reply field 
			buff[14] = 0x00;    buff[15] = 0x00;								//		- Timestamp Echo Reply field (continued)

			buff[16] = 0x01;													// RFC 0793 : nop

			buff[17] = 0x03; buff[18] = 0x03; buff[19] = 0x02;					// RFC 1323 : Window Scale Option, length = 3

			retVal = 20;
			break;

		case __mosSolaris_8:
			retVal = 0;
			break;

		case __mosNevada35:
			buff[0] = 0x02; buff[1] = 0x04; buff[2] = 0x05; buff[3] = 0xA0;	// RFC 0793 : Maximum Segment Size, length = 4
			buff[4] = 0x01;													// RFC 0793 : nop
			buff[5] = 0x03; buff[6] = 0x03; buff[7] = 0x00;					// RFC 1323 : Window Scale Option, length = 3
			buff[8] = 0x01;													// RFC 0793 : nop
			buff[9] = 0x01;													// RFC 0793 : nop
			buff[10] = 0x04; buff[11] = 0x02;								// RFC 2018 : Sack-Permitted Option, length = 2

			retVal = 12;
			break;

		default:
			retVal = 0;
			break;
	}

	return retVal;
}
//---------------------------------------------------------------------------

int PacketBuilderEx6::BuildIcmpEchoDataBuffer(BYTE* dataIn)
{
	__time64_t lTime;
	DWORD valD;
	BYTE* bbb;
	BYTE val;
	int i;

	int retVal;

	if(dataIn==NULL) return 0;

	MimicOS myMimic;

	myMimic = mimicInfoPack.GetMimic();

	switch(myMimic){
		case __mosWindowsXPSP2 :
			for(i=0; i<32; i++){
				val = 0x61 + i;
				if(val>0x77)
					val -= 0x17;
				dataIn[i] = val;
			}

			retVal = 32;
			break;

		case __mosWindows2K3 :
			for(i=0; i<32; i++){
				val = 0x61 + i;
				if(val>0x77)
					val -= 0x17;
				dataIn[i] = val;
			}

			retVal = 32;
			break;

		case __mosLinux_2_4:
		case __mosSolaris_8:
			// TODO: Rough guess !!!
			_time64(&lTime);

			valD = (DWORD) (lTime & 0xFFFFFFFF);
			bbb = (BYTE*)&valD;
			dataIn[0] = bbb[0];
			dataIn[1] = bbb[1];
			dataIn[2] = bbb[2];
			dataIn[3] = bbb[3];

			valD = GetTickCount();
			bbb = (BYTE*)&valD;
			dataIn[4] = bbb[0];
			dataIn[5] = bbb[1];
			dataIn[6] = bbb[2];
			dataIn[7] = bbb[3];

			for(i=8; i<56; i++)
				dataIn[i] = (BYTE)i;

			retVal = 56;
			break;

		case __mosLinux_2_6:
			_time64(&lTime);

			valD = (DWORD) (lTime & 0xFFFFFFFF);
			bbb = (BYTE*)&valD;
			dataIn[0] = bbb[3];
			dataIn[1] = bbb[2];
			dataIn[2] = bbb[1];
			dataIn[3] = bbb[0];

			valD = GetTickCount();
			bbb = (BYTE*)&valD;
			dataIn[4] = bbb[3];
			dataIn[5] = bbb[2];
			dataIn[6] = bbb[1];
			dataIn[7] = bbb[0];

			for(i=8; i<56; i++)
				dataIn[i] = (BYTE)i;

			retVal = 56;
			break;

		case __mosNevada35 :
			_time64(&lTime);

			valD = (DWORD) (lTime & 0xFFFFFFFF);
			bbb = (BYTE*)&valD;
			dataIn[0] = bbb[3];
			dataIn[1] = bbb[2];
			dataIn[2] = bbb[1];
			dataIn[3] = bbb[0];

			valD = GetTickCount();
			bbb = (BYTE*)&valD;
			dataIn[4] = bbb[3];
			dataIn[5] = bbb[2];
			dataIn[6] = bbb[1];
			dataIn[7] = bbb[0];

			for(i=8; i<56; i++)
				dataIn[i] = (BYTE)i;

			retVal = 56;
			break;

		default:
			memset(dataIn, 0, 56);
			retVal = 56;
			break;
	}

	return retVal;
}

//---------------------------------------------------------------------------

bool PacketBuilderEx6::BuildPackTcpSyn(
		in_addr6* srcAddrIn,	///< source address
		in_addr6* dstAddrIn,    ///< destination address
		WORD wDP,               ///< destination port
		DWORD dwSeq             ///< sequence
	)
{
	bool retVal;
	BYTE optBuff[20];
	int optBuffSize;

	if(srcAddrIn==NULL) return false;
	if(dstAddrIn==NULL) return false;

	optBuffSize = BuildSynOptions(&optBuff[0]);

	mimicInfoPack.GetNewSet6(&mimicInfo, __miipTcp);

	retVal = BuildPacketTCP(
				srcAddrIn,
				dstAddrIn,
				mimicInfo.bTrafficClass6, 
				mimicInfo.dwFlowLabel6, 
				mimicInfo.bHopLimit6_Gen, 
				mimicInfo.srcPort,
				wDP,
				dwSeq,
				0x00000000, 
				TH_SYN, 
				mimicInfo.wWindow6,
				0x0000,
				optBuff, (DWORD)optBuffSize,
				NULL, 0);

	return retVal;
}

bool PacketBuilderEx6::BuildPackTcpFlat(
		in_addr6* srcAddrIn,		///< source address
		in_addr6* dstAddrIn,		///< destination address
		WORD wDP,					///< destination port
		DWORD dwSeq,			    ///< sequence
		DWORD dwAck,				///< acknowledge
		BYTE  bFlags				///< flags
	)
{
	bool retVal;

	if(srcAddrIn==NULL) return false;
	if(dstAddrIn==NULL) return false;

	mimicInfoPack.GetNewSet6(&mimicInfo, __miipTcp);

	retVal = BuildPacketTCP(
				srcAddrIn,
				dstAddrIn,
				mimicInfo.bTrafficClass6, 
				mimicInfo.dwFlowLabel6, 
				mimicInfo.bHopLimit6_Gen, 
				mimicInfo.srcPort,
				wDP,
				dwSeq,
				dwAck, 
				bFlags, 
				mimicInfo.wWindow6,
				0x0000,
				NULL, 0,
				NULL, 0);

	return retVal;
}

bool PacketBuilderEx6::BuildPackTcpFlatWithSrcPort(
		in_addr6* srcAddrIn,		///< source address
		in_addr6* dstAddrIn,		///< destination address
		WORD wSP,					///< source port
		WORD wDP,					///< destination port
		DWORD dwSeq,			    ///< sequence
		DWORD dwAck,				///< acknowledge
		BYTE  bFlags				///< flags
	)
{
	bool retVal;

	if(srcAddrIn==NULL) return false;
	if(dstAddrIn==NULL) return false;

	mimicInfoPack.GetNewSet6(&mimicInfo, __miipTcp);

	retVal = BuildPacketTCP(
				srcAddrIn,
				dstAddrIn,
				mimicInfo.bTrafficClass6, 
				mimicInfo.dwFlowLabel6, 
				mimicInfo.bHopLimit6_Gen, 
				wSP,
				wDP,
				dwSeq,
				dwAck, 
				bFlags, 
				mimicInfo.wWindow6,
				0x0000,
				NULL, 0,
				NULL, 0);

	return retVal;
}

//---------------------------------------------------------------------------

bool PacketBuilderEx6::BuildPackUDPFlat(
		in_addr6* srcAddrIn,		///< source address
		in_addr6* dstAddrIn,		///< destination address
		WORD wDP					///< destination port
	)
{
	bool retVal;

	if(srcAddrIn==NULL) return false;
	if(dstAddrIn==NULL) return false;

	mimicInfoPack.GetNewSet6(&mimicInfo, __miipUdp);

	retVal = BuildPacketUDP(
				srcAddrIn,
				dstAddrIn,
				mimicInfo.bTrafficClass6, 
				mimicInfo.dwFlowLabel6, 
				mimicInfo.bHopLimit6_Gen, 
				mimicInfo.srcPort,
				wDP,
				NULL, 0);

	return retVal;
}

//---------------------------------------------------------------------------

bool PacketBuilderEx6::BuildPackIcmpEchoRequest(
			in_addr6* srcAddrIn,		///< source address
			in_addr6* dstAddrIn			///< destination address
		)
{
	BYTE buff[56];
	bool retVal;
	int buffSize;

	if(srcAddrIn==NULL) return false;
	if(dstAddrIn==NULL) return false;

	buffSize = BuildIcmpEchoDataBuffer(&buff[0]);
	
	mimicInfoPack.GetNewSet6(&mimicInfo, __miipIcmp);

	retVal = BuildPacketICMPEcho(
		srcAddrIn,
		dstAddrIn,
		mimicInfo.bTrafficClass6,
		mimicInfo.dwFlowLabel6,
		mimicInfo.bHopLimit6_Gen,
		true,
		mimicInfo.wIcmpId6,
		mimicInfo.wIcmpSeq6,
		buff,
		(DWORD)buffSize);
		
	return retVal;
}

bool PacketBuilderEx6::BuildPackIcmpEchoRequestWithUserData(
			in_addr6* srcAddrIn,		///< source address
			in_addr6* dstAddrIn, 		///< destination address
			BYTE* dataIn,				///< payload
			int sizeIn					///< payload's size
		)
{
	bool retVal;

	if(srcAddrIn==NULL) return false;
	if(dstAddrIn==NULL) return false;
	if(dataIn==NULL && sizeIn!=0) return false;

	mimicInfoPack.GetNewSet6(&mimicInfo, __miipIcmp);

	retVal = BuildPacketICMPEcho(
		srcAddrIn,
		dstAddrIn,
		mimicInfo.bTrafficClass6,
		mimicInfo.dwFlowLabel6,
		mimicInfo.bHopLimit6_Gen,
		true,
		mimicInfo.wIcmpId6,
		mimicInfo.wIcmpSeq6,
		dataIn,
		(DWORD)sizeIn);

	return retVal;
}

//---------------------------------------------------------------------------

bool PacketBuilderEx6::BuildPacketEmptyIPv6ProtoFlat(
			in_addr6* srcAddrIn,			///< source address
			in_addr6* dstAddrIn,			///< destination address
			BYTE      bNextHeaderIn		///< next header
		)
{
	bool retVal;

	if(srcAddrIn==NULL) return false;
	if(dstAddrIn==NULL) return false;

	switch(bNextHeaderIn){
		case IPPROTO_TCP :
			mimicInfoPack.GetNewSet6(&mimicInfo, __miipTcp);
			break;

		case IPPROTO_UDP :
			mimicInfoPack.GetNewSet6(&mimicInfo, __miipUdp);
			break;

		case 0x3A:	// ICMPv6
			mimicInfoPack.GetNewSet6(&mimicInfo, __miipIcmp);
			break;

		default:
			mimicInfoPack.GetNewSet6(&mimicInfo, __miipTcp);
			break;
	}

	retVal = BuildPacketEmptyIPv6Proto(
		srcAddrIn,
		dstAddrIn,
		mimicInfo.bTrafficClass6,
		mimicInfo.dwFlowLabel6,
		mimicInfo.bHopLimit6_Gen,
		bNextHeaderIn);

	return retVal;
}

//---------------------------------------------------------------------------
